//    Openbravo POS is a point of sales application designed for touch screens.
//    Copyright (C) 2007-2009 Openbravo, S.L.
//    http://www.openbravo.com/product/pos
//
//    This file is part of Openbravo POS.
//
//    Openbravo POS is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    Openbravo POS is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with Openbravo POS.  If not, see <http://www.gnu.org/licenses/>.

package com.openbravo.pos.printer.printer;

import java.awt.Component;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.print.Doc;
import javax.print.DocFlavor;
import javax.print.DocPrintJob;
import javax.print.PrintException;
import javax.print.PrintService;
import javax.print.SimpleDoc;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.standard.JobName;
import javax.print.attribute.standard.Media;
import javax.print.attribute.standard.MediaSizeName;
import javax.print.attribute.standard.OrientationRequested;
import javax.swing.JComponent;

import com.openbravo.pos.forms.AppLocal;
import com.openbravo.pos.printer.DevicePrinter;
import com.openbravo.pos.printer.ticket.BasicTicket;
import com.openbravo.pos.printer.ticket.BasicTicketForPrinter;
import com.openbravo.pos.util.ReportUtils;
import com.openbravo.pos.util.SelectPrinter;

/**
 * Class DevicePrinterPrinter is responsible for printing tickets using system <br>
 * printers. It takes into consideration if a user set a printer as a receipt <br>
 * printer or not.
 * <p>
 * For receipt printers lenght of a receipt must be calculated in this class.
 * </p>
 * <p>
 * For normal printers number of pages must be calculated dynamically in the <br>
 * class PrintableTicket @see com.openbravo.pos.printer.printer.PrintableTicket
 * 
 * @author jaroslawwozniak
 */
public class DevicePrinterPrinter implements DevicePrinter {

	private static Logger logger = Logger.getLogger("com.openbravo.pos.printer.printer.DevicePrinterPrinter");

	private Component parent;
	/*name of a printer*/
	private String m_sName;
	/*a ticket to print*/
	private BasicTicket m_ticketcurrent;
	/*system printer*/
	private PrintService printservice;

	//    // For Page Size 72mm x 200mm && MediaSizeName A4.
	//    private static final int imageable_width = 190;
	//    private static final int imageable_height = 546;
	//    private static final int imageable_x = 10;
	//    private static final int imageable_y = 287;
	//    private static final Media media = MediaSizeName.ISO_A4;

	//    // For Page Size A4 && MediaSizeName A4.
	//    private static final int imageable_width = 451;
	//    private static final int imageable_height = 698;
	//    private static final int imageable_x = 72;
	//    private static final int imageable_y = 72;
	//    private static final Media media = MediaSizeName.ISO_A4;

	private int imageable_width;
	private int imageable_height;
	private int imageable_x;
	private int imageable_y;
	private Media media;

	private static final HashMap<String, MediaSizeName> mediasizenamemap = new HashMap<String, MediaSizeName>();

	/**
	 * Creates a new instance of DevicePrinterPrinter
	 * 
	 * @param printername
	 *            - name of printer that will be called in the system
	 * @param isReceiptPrinter
	 *            - string with boolean values if the printer is a receipt
	 */
	public DevicePrinterPrinter(Component parent, String printername, int imageable_x, int imageable_y,
			int imageable_width, int imageable_height, String mediasizename) {

		this.parent = parent;
		m_sName = "Printer"; // "AppLocal.getIntString("Printer.Screen");
		m_ticketcurrent = null;
		printservice = ReportUtils.getPrintService(printername);

		this.imageable_x = imageable_x;
		this.imageable_y = imageable_y;
		this.imageable_width = imageable_width;
		this.imageable_height = imageable_height;
		this.media = getMedia(mediasizename);
	}

	/**
	 * Getter that returns the name of a printer
	 * 
	 * @return m_sName a name of a printer
	 */
	@Override
	public String getPrinterName() {
		return m_sName;
	}

	/**
	 * Getter that returns the description of a printer
	 * 
	 * @return decription of a printer
	 */
	@Override
	public String getPrinterDescription() {
		return null;
	}

	/**
	 * Getter that returns the printer's component
	 * 
	 * @return printer's component
	 */
	@Override
	public JComponent getPrinterComponent() {
		return null;
	}

	/**
	 * Method that sets the current ticket as a null
	 */
	@Override
	public void reset() {
		m_ticketcurrent = null;
	}

	/**
	 * Method that is responsible for start a new ticket
	 */
	@Override
	public void beginReceipt() {
		m_ticketcurrent = new BasicTicketForPrinter();
	}

	/**
	 * Method that is responsible for printing an image
	 * 
	 * @param image
	 *            a buffered image object
	 */
	@Override
	public void printImage(BufferedImage image) {
		m_ticketcurrent.printImage(image);
	}

	/**
	 * Method that is responsible for printing a barcode
	 * 
	 * @param type
	 *            a type of a barcode
	 * @param position
	 *            coordinates of a barcode on a receipt
	 * @param code
	 *            the code of a productmiale
	 */
	@Override
	public void printBarCode(String type, String position, String code) {
		m_ticketcurrent.printBarCode(type, position, code);
	}

	/**
	 * Method that is responsible for starting a new line on a receipt
	 * 
	 * @param iTextSize
	 *            a size of text in the line
	 */
	@Override
	public void beginLine(int iTextSize) {
		m_ticketcurrent.beginLine(iTextSize);
	}

	/**
	 * Method that is responsible for printing text
	 * 
	 * @param iStyle
	 *            style of text
	 * @param sText
	 *            text to print
	 */
	@Override
	public void printText(int iStyle, String sText) {
		m_ticketcurrent.printText(iStyle, sText);
	}

	/**
	 * Method that is responsible for ending a line
	 */
	@Override
	public void endLine() {
		m_ticketcurrent.endLine();
	}

	/**
	 * Method that is responsible for ending and printing a ticket<br>
	 * It manages to get a printerJob, set the name of the job, get a Book object<br>
	 * and print the receipt
	 */
	@Override
	public void endReceipt() {

		try {

			PrintService ps;

			if (printservice == null) {
				String[] printers = ReportUtils.getPrintNames();
				if (printers.length == 0) {
					logger.warning(AppLocal.getIntString("message.noprinters"));
					ps = null;
				}
				else {
					SelectPrinter selectprinter = SelectPrinter.getSelectPrinter(parent, printers);
					selectprinter.setVisible(true);
					if (selectprinter.isOK()) {
						ps = ReportUtils.getPrintService(selectprinter.getPrintService());
					}
					else {
						ps = null;
					}
				}
			}
			else {
				ps = printservice;
			}

			if (ps != null) {

				PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
				aset.add(OrientationRequested.PORTRAIT);
				aset.add(new JobName(AppLocal.APP_NAME + " - Document", null));
				aset.add(media);

				DocPrintJob printjob = ps.createPrintJob();
				Doc doc = new SimpleDoc(new PrintableBasicTicket(m_ticketcurrent, imageable_x, imageable_y,
						imageable_width, imageable_height), DocFlavor.SERVICE_FORMATTED.PRINTABLE, null);

				printjob.print(doc, aset);
			}

		}
		catch (PrintException ex) {
			logger.log(Level.WARNING, AppLocal.getIntString("message.printererror"), ex);
			// FIXME throw this exception         
			//            JMessageDialog.showMessage(parent, new MessageInf(MessageInf.SGN_WARNING, AppLocal.getIntString("message.printererror"), ex));
		}

		//ticket is not needed any more
		m_ticketcurrent = null;
	}

	/**
	 * Method that is responsible for opening a drawer
	 */
	@Override
	public void openDrawer() {
		// Una simulacion
		Toolkit.getDefaultToolkit().beep();
	}

	private static MediaSizeName getMedia(String mediasizename) {
		return mediasizenamemap.get(mediasizename);
	}

	static {
		mediasizenamemap.put("Postcard", MediaSizeName.JAPANESE_POSTCARD);
		mediasizenamemap.put("Statement", MediaSizeName.INVOICE);

		mediasizenamemap.put("Letter", MediaSizeName.NA_LETTER);
		mediasizenamemap.put("Executive", MediaSizeName.EXECUTIVE);
		mediasizenamemap.put("Legal", MediaSizeName.NA_LEGAL);

		mediasizenamemap.put("A0", MediaSizeName.ISO_A0);
		mediasizenamemap.put("A1", MediaSizeName.ISO_A1);
		mediasizenamemap.put("A2", MediaSizeName.ISO_A2);
		mediasizenamemap.put("A3", MediaSizeName.ISO_A3);
		mediasizenamemap.put("A4", MediaSizeName.ISO_A4);
		mediasizenamemap.put("A5", MediaSizeName.ISO_A5);
		mediasizenamemap.put("A6", MediaSizeName.ISO_A6);
		mediasizenamemap.put("A7", MediaSizeName.ISO_A7);
		mediasizenamemap.put("A8", MediaSizeName.ISO_A8);
		mediasizenamemap.put("A9", MediaSizeName.ISO_A9);
		mediasizenamemap.put("A10", MediaSizeName.ISO_A10);

		mediasizenamemap.put("B0", MediaSizeName.JIS_B0);
		mediasizenamemap.put("B1", MediaSizeName.JIS_B1);
		mediasizenamemap.put("B2", MediaSizeName.JIS_B2);
		mediasizenamemap.put("B3", MediaSizeName.JIS_B3);
		mediasizenamemap.put("B4", MediaSizeName.JIS_B4);
		mediasizenamemap.put("B5", MediaSizeName.JIS_B5);
		mediasizenamemap.put("B6", MediaSizeName.JIS_B6);
		mediasizenamemap.put("B7", MediaSizeName.JIS_B7);
		mediasizenamemap.put("B8", MediaSizeName.JIS_B8);
		mediasizenamemap.put("B9", MediaSizeName.JIS_B9);
		mediasizenamemap.put("B10", MediaSizeName.JIS_B10);

		mediasizenamemap.put("ISOB0", MediaSizeName.ISO_B0);
		mediasizenamemap.put("ISOB1", MediaSizeName.ISO_B1);
		mediasizenamemap.put("ISOB2", MediaSizeName.ISO_B2);
		mediasizenamemap.put("ISOB3", MediaSizeName.ISO_B3);
		mediasizenamemap.put("ISOB4", MediaSizeName.ISO_B4);
		mediasizenamemap.put("ISOB5", MediaSizeName.ISO_B5);
		mediasizenamemap.put("ISOB6", MediaSizeName.ISO_B6);
		mediasizenamemap.put("ISOB7", MediaSizeName.ISO_B7);
		mediasizenamemap.put("ISOB8", MediaSizeName.ISO_B8);
		mediasizenamemap.put("ISOB9", MediaSizeName.ISO_B9);
		mediasizenamemap.put("ISOB10", MediaSizeName.ISO_B10);
		mediasizenamemap.put("EnvISOB0", MediaSizeName.ISO_B0);
		mediasizenamemap.put("EnvISOB1", MediaSizeName.ISO_B1);
		mediasizenamemap.put("EnvISOB2", MediaSizeName.ISO_B2);
		mediasizenamemap.put("EnvISOB3", MediaSizeName.ISO_B3);
		mediasizenamemap.put("EnvISOB4", MediaSizeName.ISO_B4);
		mediasizenamemap.put("EnvISOB5", MediaSizeName.ISO_B5);
		mediasizenamemap.put("EnvISOB6", MediaSizeName.ISO_B6);
		mediasizenamemap.put("EnvISOB7", MediaSizeName.ISO_B7);
		mediasizenamemap.put("EnvISOB8", MediaSizeName.ISO_B8);
		mediasizenamemap.put("EnvISOB9", MediaSizeName.ISO_B9);
		mediasizenamemap.put("EnvISOB10", MediaSizeName.ISO_B10);

		mediasizenamemap.put("C0", MediaSizeName.ISO_C0);
		mediasizenamemap.put("C1", MediaSizeName.ISO_C1);
		mediasizenamemap.put("C2", MediaSizeName.ISO_C2);
		mediasizenamemap.put("C3", MediaSizeName.ISO_C3);
		mediasizenamemap.put("C4", MediaSizeName.ISO_C4);
		mediasizenamemap.put("C5", MediaSizeName.ISO_C5);
		mediasizenamemap.put("C6", MediaSizeName.ISO_C6);

		mediasizenamemap.put("EnvPersonal", MediaSizeName.PERSONAL_ENVELOPE);
		mediasizenamemap.put("EnvMonarch", MediaSizeName.MONARCH_ENVELOPE);
		mediasizenamemap.put("Monarch", MediaSizeName.MONARCH_ENVELOPE);
		mediasizenamemap.put("Env9", MediaSizeName.NA_NUMBER_9_ENVELOPE);
		mediasizenamemap.put("Env10", MediaSizeName.NA_NUMBER_10_ENVELOPE);
		mediasizenamemap.put("Env11", MediaSizeName.NA_NUMBER_11_ENVELOPE);
		mediasizenamemap.put("Env12", MediaSizeName.NA_NUMBER_12_ENVELOPE);
		mediasizenamemap.put("Env14", MediaSizeName.NA_NUMBER_14_ENVELOPE);
		mediasizenamemap.put("c8x10", MediaSizeName.NA_8X10);

		mediasizenamemap.put("EnvDL", MediaSizeName.ISO_DESIGNATED_LONG);
		mediasizenamemap.put("DL", MediaSizeName.ISO_DESIGNATED_LONG);
		mediasizenamemap.put("EnvC0", MediaSizeName.ISO_C0);
		mediasizenamemap.put("EnvC1", MediaSizeName.ISO_C1);
		mediasizenamemap.put("EnvC2", MediaSizeName.ISO_C2);
		mediasizenamemap.put("EnvC3", MediaSizeName.ISO_C3);
		mediasizenamemap.put("EnvC4", MediaSizeName.ISO_C4);
		mediasizenamemap.put("EnvC5", MediaSizeName.ISO_C5);
		mediasizenamemap.put("EnvC6", MediaSizeName.ISO_C6);
	}
}